﻿using System;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;

namespace Spacer {
	public enum Platform {
		Windows,
		XBOX360
	}

	public enum DialogResult : uint {
		None = 0,
		OK = 1,
		Cancel = 2,
		Abort = 3,
		Retry = 4,
		Ignore = 5,
		Yes = 6,
		No = 7
	}

	public enum MessageBoxButtons : uint {
		OK = 0,
		OKCancel = 1,
		AbortRetryIgnore = 2,
		YesNoCancel = 3,
		YesNo = 4,
		RetryCancel = 5
	}

	// ----------

	/// <summary>
	/// Holds static global variables and methods
	/// </summary>
	public static class Globals {
		/// <summary>
		/// Initializes Globals' static variables
		/// </summary>
		public static void Initialize( Main instance ) {
			GameInstance = instance;

			ThreadSync = new Object();
			Activities = new Stack<Activity>();
			PushActivity( new MainMenu() );
		}

		/// <summary>
		/// Pushes an Activity onto the activities stack.
		/// Only the TOP Activity receives calls from Game::Update() and Game::Draw().
		/// </summary>
		/// <param name="activity">The Activity to push.</param>
		/// <returns>Success or failure.</returns>
		public static bool PushActivity( Activity activity ) {
			if( activity == null )
				return false;

			//ThreadSync.WaitOne();
			lock( ThreadSync ) {

				Activity current = (Activities.Count > 0 ? Activities.Peek() : null);
				if( current != null ) {

					// If the current is a 'Modal' Activity (Forced to be the only TOP Activity until popped) then return failure
					if( current.IsModal() )
						return false;
				
					// Push and initialize the new top Activity
					Activities.Push( activity );
					activity.Initialize();

					// Not a modal, tell it that it is being paused
					current.Paused();

				} else {

					// No previous activity to pause,
					// Push and initialize the new top Activity
					Activities.Push( activity );
					activity.Initialize();

				}

			}
			//ThreadSync.Release();

			return true;
		}

		/// <summary>
		/// Should only be used internally by the Activity system (Can't think of any special cases, yet).
		/// </summary>
		public static Activity PopActivity() {
			Activity removed;

			//ThreadSync.WaitOne();
			lock( ThreadSync ) {

				// Pop TOP Activity and tell it that it is being shutdown
				removed = (Activities.Count > 0 ? Activities.Pop() : null);
				if( removed != null )
					removed.Shutdown();

				// Pop TOP Activity and tell it that it is being shutdown
				Activity top = (Activities.Count > 0 ? Activities.Peek() : null);
				if( top != null )
					top.Resumed();

			}
			//ThreadSync.Release();

			return removed;
		}

		public static List<Activity> CurrentActivities() {
			List<Activity> current = new List<Activity>();
			
			//ThreadSync.WaitOne();
			lock( ThreadSync ) {
				Activity[] stack = Activities.ToArray();
				for(int i=0;i<Activities.Count;i++) {
					current.Add( stack[i] );
					if( !stack[i].IsTransparent() )
						break;
				}
			}
			//ThreadSync.Release();

			current.Reverse();
			return current;
		}
		
		/// <summary>
		/// Returns a randomly generated int within a range NOT using the current seeds!
		/// </summary>
		public static int GetRandomRange( int min, int max ) {
			return s_Random.Next( min, max );
		}
		
		/// <summary>
		/// Returns a randomly generated float within a range NOT using the current seeds!
		/// </summary>
		public static float GetRandomRange( float min, float max ) {
			return (max-min) * (float)s_Random.NextDouble() + min;
		}

		#if !XBOX360
		[DllImport("user32.dll", CharSet = CharSet.Auto)]
		public static extern uint MessageBox( IntPtr hWnd, String text, String caption, uint type );
		#else
		public static uint MessageBox( IntPtr hWnd, String text, String caption, uint type ) {
			if( !Globals.GamerServicesEnabled )
				return 0;

			//Guide.BeginShowMessageBox( caption, text, 

			return 0;
		}
		#endif

		// ----------
		
		/// <summary>
		/// Returns the current running platform
		/// </summary>
		#if !XBOX360
		public static Platform Platform { get { return Platform.Windows; } }
		#else
		public static Platform Platform { get { return Platform.XBOX360; } }
		#endif

		public static bool GamerServicesEnabled { get; set; }

		public static PlayerController LocalPlayer { get; set; }

		public static StorageContainer LocalStorage { get; set; }

		/// <summary>
		/// Reference to Game instance.
		/// Is this needed?
		/// </summary>
		public static Main GameInstance { get; set; }

		/// <summary>
		/// Current game time
		/// </summary>
		public static float GameTime { get; set; }

		/// <summary>
		/// Time since last Update()
		/// </summary>
		public static float UpdateDeltaTime { get; set; }

		/// <summary>
		/// Time since last Draw()
		/// </summary>
		public static float DrawDeltaTime { get; set; }

		/// <summary>
		/// Returns a randomly generated float NOT using the current seeds!
		/// </summary>
		public static float Random { get { return (float)s_Random.NextDouble(); } }

		/// <summary>
		/// Stack of activities that are active or waiting to become active.
		/// </summary>

		/// <summary>
		/// The currently active activity (Top of stack).
		/// </summary>
		public static Activity CurrentActivity { get { Activity ret; lock(ThreadSync) { ret = Activities.Peek(); } return ret; } }
		
		/// <summary>
		/// The currently loaded and active galaxy session.
		/// </summary>
		public static GalaxySession CurrentSession { get; set; }

		public static float ALOTf { get { return Single.MaxValue; } }

		#region Debug stuff
		/// <summary>
		/// Returns if we are in a debug build
		/// </summary>
		#if !DEBUG
		public static bool IsDebug { get { return false; } }
		#else
		public static bool IsDebug { get { return true; } }
		#endif

		public static void DebugPrint( params object[] msg ) {
		#if DEBUG
			StackTrace trace = new StackTrace();
			MethodBase method = trace.GetFrame( 1 ).GetMethod();
			string strClass = method.DeclaringType.Name;
			string strMethod = method.Name;

			Console.Write( strClass + "::" + strMethod + " - " );
			foreach(object obj in msg) {
				Console.Write( obj.ToString() );
			}
			Console.Write( "\n" );
		#else
			return;
		#endif
		}
		#endregion

		// ----------
		
		private static Stack<Activity> Activities { get; set; }
		private static Object ThreadSync { get; set; }

		private static Random s_Random = new Random();
	}
}
